using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LDNS.SDK.Formatting
{
    /// <summary>
    /// 文本表格格式化器
    /// 作者：huobing
    /// </summary>
    public static class TextTableFormatter
    {
        /// <summary>
        /// 格式化对齐表格，每列宽度按当前列的最大长度计算，考虑中文、英文、中文空格和英文空格
        /// </summary>
        /// <param name="rows">表格数据行</param>
        /// <param name="paddingChar">列之间的分隔字符</param>
        /// <param name="maxColumnWidth">每列的最大显示宽度</param>
        /// <returns>格式化后的表格字符串</returns>
        public static string FormatAlignedTable(IReadOnlyList<string[]> rows, char paddingChar = ' ', int maxColumnWidth = 80)
        {
            if (rows == null || rows.Count == 0) return string.Empty;
            int columnCount = rows.Max(r => r.Length);
            var widths = new int[columnCount];
            // 计算每列的最大显示宽度（考虑中文、英文、中文空格和英文空格）
            for (int i = 0; i < columnCount; i++)
            {
                widths[i] = rows.Max(r => i < r.Length ? GetDisplayWidth(r[i]) : 0);
                if (widths[i] > maxColumnWidth) widths[i] = maxColumnWidth;
            }
            var sb = new StringBuilder();
            foreach (var row in rows)
            {
                for (int i = 0; i < columnCount; i++)
                {
                    var cell = i < row.Length ? (row[i] ?? string.Empty) : string.Empty;
                    // 使用显示宽度截断字符串
                    cell = TruncateByDisplayWidth(cell, maxColumnWidth);
                    // 使用空格填充到列宽
                    sb.Append(cell + new string(' ', widths[i] - GetDisplayWidth(cell)));
                    if (i < columnCount - 1) sb.Append(paddingChar);
                }
                sb.AppendLine();
            }
            return sb.ToString().TrimEnd();
        }
        
        /// <summary>
        /// 计算字符串的显示宽度，考虑中文（全宽字符）占用2个单位，英文（半宽字符）占用1个单位
        /// </summary>
        /// <param name="str">要计算宽度的字符串</param>
        /// <returns>字符串的显示宽度</returns>
        public static int GetDisplayWidth(string str)
        {
            if (string.IsNullOrEmpty(str)) return 0;
            
            int width = 0;
            foreach (char c in str)
            {
                // 判断是否为全宽字符（包括中文字符、中文空格等）
                if (IsFullWidth(c))
                {
                    width += 2;
                }
                else
                {
                    width += 1;
                }
            }
            
            return width;
        }
        
        /// <summary>
        /// 判断字符是否为全宽字符
        /// </summary>
        /// <param name="c">要判断的字符</param>
        /// <returns>是否为全宽字符</returns>
        private static bool IsFullWidth(char c)
        {
            // Unicode全宽字符范围
            // 中文、日文、韩文字符范围
            if (c >= 0x4E00 && c <= 0x9FFF) return true;
            // 中文全角标点符号范围
            if (c >= 0xFF01 && c <= 0xFF5E) return true;
            // 中文全角空格
            if (c == 0x3000) return true;
            // 其他可能的全宽字符范围
            if (c >= 0xFFE0 && c <= 0xFFE6) return true;
            // 其他CJK扩展字符范围
            if (c >= 0x3400 && c <= 0x4DBF) return true;
            if (c >= 0x20000 && c <= 0x2A6DF) return true;
            if (c >= 0x2A700 && c <= 0x2B73F) return true;
            if (c >= 0x2B740 && c <= 0x2B81F) return true;
            if (c >= 0x2B820 && c <= 0x2CEAF) return true;
            
            return false;
        }
        
        /// <summary>
        /// 根据显示宽度截断字符串
        /// </summary>
        /// <param name="str">要截断的字符串</param>
        /// <param name="maxWidth">最大显示宽度</param>
        /// <returns>截断后的字符串</returns>
        private static string TruncateByDisplayWidth(string str, int maxWidth)
        {
            if (string.IsNullOrEmpty(str)) return str;
            if (maxWidth <= 0) return string.Empty;
            
            int currentWidth = 0;
            int i = 0;
            
            for (; i < str.Length; i++)
            {
                int charWidth = IsFullWidth(str[i]) ? 2 : 1;
                if (currentWidth + charWidth > maxWidth)
                {
                    break;
                }
                currentWidth += charWidth;
            }
            
            return str.Substring(0, i);
        }
    }
}